package org.example.java8.parallel;

import java.util.Objects;
import java.util.Optional;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * @author 夏焰波
 * @date 2020-07-15 0:21
 */
public class SpliteratorInAction {
    private static String text = "Every Sunday morning I take a light jog around a park near my home. " +
            "\n" +
            "There’s a lake located in one corner of the park. " +
            "\n" +
            "Each time I jog by this lake, " +
            "\n" +
            "I see the same elderly woman sitting at the water’s edge with a small metal cage sitting beside her.";

    public static void main(String[] args) {
        //test();

        MySpliteratorText mySpliteratorText = new MySpliteratorText(text);
        Optional.ofNullable(mySpliteratorText.stream().count())
                .ifPresent(System.out::println);
        //mySpliteratorText.stream().forEach(System.out::println);

        mySpliteratorText.stream().filter(s -> !s.equals("")).forEach(System.out::println);

        IntStream intStream = IntStream.rangeClosed(0, 100);
        //并行，串行改变的是this.sourceStage.parallel(true/false)，生效的是最后一次改变
        //intStream.parallel().sequential().parallel().filter(null).forEach(null);
    }

    private static void test() {
        IntStream intStream = IntStream.rangeClosed(0, 10);
        Spliterator.OfInt spliterator = intStream.spliterator();

        Consumer<Integer> consumer = i -> System.out.println(i);
        spliterator.forEachRemaining(consumer);
    }

    static class MySpliteratorText {
        private final String[] data;

        public MySpliteratorText(String text) {
            Objects.requireNonNull(text, "the parameter can not be null");
            this.data = text.split("\n");
        }

        public Stream<String> stream() {
            return StreamSupport.stream(new MySpliterator(), false);
        }

        public Stream<String> parallelStream() {
            return StreamSupport.stream(new MySpliterator(), true);
        }

        private class MySpliterator implements Spliterator<String> {
            private int start, end;

            public MySpliterator() {
                this.start = 0;
                //this.end = MySpliteratorText.this.data.length - 1;
                this.end = MySpliteratorText.this.data.length;
            }

            public MySpliterator(int start, int end) {
                this.start = start;
                this.end = end;
            }

            /**
             * 不管stream是并行还是非并行的都会调用tryAdvance
             */
            @Override
            public boolean tryAdvance(Consumer<? super String> consumer) {
                //if (start <= end) {
                if (start < end) {
                    consumer.accept(MySpliteratorText.this.data[start++]);
                    return true;
                }
                return false;
            }

            /**
             * 并行调用trySplit
             */
            @Override
            public Spliterator<String> trySplit() {
                int mid = (end - start) / 2;
                if (mid <= 1) {
                    return null;
                }
                int left = start;
                int right = start + mid;
                start = start + mid + 1;

                return new MySpliterator(left, right);
            }

            @Override
            //有没有元素
            public long estimateSize() {
                return end - start;
            }

            @Override
            public long getExactSizeIfKnown() {
                return estimateSize();
            }

            @Override
            public int characteristics() {
                //不可变的、大小固定、可以取子集
                return IMMUTABLE | SIZED | SUBSIZED;
            }
        }

    }
}
